using Godot;
using System;

namespace CurrentGame.Utils.Interpolation;


public class LerpInterpolation
{
    public delegate void ReachStableValueEventHandler(float v, Vector2 v2, Vector3 v3);
    public event ReachStableValueEventHandler ReachStableValue;

    public float Value
    {
        get => _value;
        set
        {
            _animating = true;
            _targetValue = value;
        }
    }
    private float _value, _targetValue;

    public Vector2 Vector2Value
    {
        get => _v2Value;
        set
        {
            _animating = true;
            _targetV2Value = value;
        }
    }
    private Vector2 _v2Value, _targetV2Value;

    public Vector3 Vector3Value
    {
        get => _v3Value;
        set
        {
            _animating = true;
            _targetV3Value = value;
        }
    }
    private Vector3 _v3Value, _targetV3Value;

    public float Weight { get; set; }

    private double _delta = 0.0f, _interval;
    private bool _animating = false;
    private bool _e1, _e2, _e3;
    private Vector3 _toleranceVector;

    public LerpInterpolation(float interval, Vector3 toleranceVector)
    {
        _interval = interval;
        _e1 = toleranceVector.X > 0.0f;
        _e2 = toleranceVector.Y > 0.0f;
        _e3 = toleranceVector.Z > 0.0f;
        _toleranceVector = toleranceVector;
    }

    private bool Update()
    {
        if (_animating)
        {
            var stable = true;

            if (_e1)
            {
                var d = _targetValue - _value;
                if (Mathf.Abs(d) > _toleranceVector.X)
                {
                    stable = false;
                    _value += d * Weight;
                }
            }

            if (_e2)
            {
                var d = _targetV2Value - _v2Value;
                if (d.LengthSquared() > _toleranceVector.Y)
                {
                    stable = false;
                    _v2Value += d * Weight;
                }
            }

            if (_e3)
            {
                var d = _targetV3Value - _v3Value;
                if (d.LengthSquared() > _toleranceVector.Z)
                {
                    stable = false;
                    _v3Value += d * Weight;
                }
            }

            if (stable)
            {
                _animating = false;
                _value = _targetValue;
                _v2Value = _targetV2Value;
                _v3Value = _targetV3Value;

                ReachStableValue?.Invoke(_value, _v2Value, _v3Value);
            }

            return true;
        }

        return false;
    }

    public bool Process(double delta)
    {
        _delta += delta;
        if (_delta > _interval)
        {
            _delta = 0;
            return Update();
        }
        return false;
    }

    public void Teleport()
    {
        _animating = false;
        _value = _targetValue;
        _v2Value = _targetV2Value;
        _v3Value = _targetV3Value;
    }
}
